<!--
Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
Code distributed by Google as part of the polymer project is also
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
-->

<link rel="import" href="../polymer/polymer.html">
<link rel="import" href="core-animation.html">

<!--
@group Polymer Core Elements

`core-animation-group` combines `core-animation` or `core-animation-group` elements to
create a grouped web animation. The group may be parallel (type is `par`) or sequential
(type is `seq`). Parallel groups play all the children elements simultaneously, and
sequential groups play the children one after another.

Example of an animation group to rotate and then fade an element:

    <core-animation-group type="seq">
      <core-animation id="fadeout" duration="500">
        <core-animation-keyframe>
          <core-animation-prop name="transform" value="rotate(0deg)"></core-animation-prop>
          <core-animation-prop name="transform" value="rotate(45deg)"></core-animation-prop>
        </core-animation-keyframe>
      </core-animation>
      <core-animation id="fadeout" duration="500">
        <core-animation-keyframe>
          <core-animation-prop name="opacity" value="1"></core-animation-prop>
        </core-animation-keyframe>
        <core-animation-keyframe>
          <core-animation-prop name="opacity" value="0"></core-animation-prop>
        </core-animation-keyframe>
      </core-animation>
    </core-animation-group>

@element core-animation-group
@status beta
@homepage github.io
-->
<polymer-element name="core-animation-group" constructor="CoreAnimationGroup" extends="core-animation" attributes="type">
  <script>
    (function() {

      var ANIMATION_GROUPS = {
        'par': AnimationGroup,
        'seq': AnimationSequence
      };

      Polymer({

        publish: {
          /**
           * If target is set, any children without a target will be assigned the group's
           * target when this property is set.
           *
           * @property target
           * @type HTMLElement|Node|Array|Array<HTMLElement|Node>
           */

          /**
           * For a `core-animation-group`, a duration of "auto" means the duration should
           * be the specified duration of its children. If set to anything other than
           * "auto", any children without a set duration will be assigned the group's duration.
           *
           * @property duration
           * @type number
           * @default "auto"
           */
          duration: {value: 'auto', reflect: true},

          /**
           * The type of the animation group. 'par' creates a parallel group and 'seq' creates
           * a sequential group.
           *
           * @property type
           * @type String
           * @default 'par'
           */
          type: {value: 'par', reflect: true}
        },

        typeChanged: function() {
          this.apply();
        },

        targetChanged: function() {
          // Only propagate target to children animations if it's defined.
          if (this.target) {
            this.doOnChildren(function(c) {
              c.target = this.target;
            }.bind(this));
          }
        },

        durationChanged: function() {
          if (this.duration && this.duration !== 'auto') {
            this.doOnChildren(function(c) {
              // Propagate to children that is not a group and has no
              // duration specified.
              if (!c.type && (!c.duration || c.duration === 'auto')) {
                c.duration = this.duration;
              }
            }.bind(this));
          }
        },

        doOnChildren: function(inFn) {
          var children = this.children;
          if (!children.length) {
            children = this.shadowRoot ? this.shadowRoot.childNodes : [];
          }
          Array.prototype.forEach.call(children, function(c) {
            // TODO <template> in the way
            c.apply && inFn(c);
          }, this);
        },

        makeAnimation: function() {
          return new ANIMATION_GROUPS[this.type](this.childAnimations, this.timingProps);
        },

        hasTarget: function() {
          var ht = this.target !== null;
          if (!ht) {
            this.doOnChildren(function(c) {
              ht = ht || c.hasTarget();
            }.bind(this));
          }
          return ht;
        },

        apply: function() {
          // Propagate target and duration to child animations first.
          this.durationChanged();
          this.targetChanged();
          this.doOnChildren(function(c) {
            c.apply();
          });
          return this.super();
        },

        get childAnimationElements() {
          var list = [];
          this.doOnChildren(function(c) {
            if (c.makeAnimation) {
              list.push(c);
            }
          });
          return list;
        },

        get childAnimations() {
          var list = [];
          this.doOnChildren(function(c) {
            if (c.animation) {
              list.push(c.animation);
            }
          });
          return list;
        }
      });

    })();
  </script>
</polymer-element>
